using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;

namespace NNFramework.NeuroLibrary
{
    public static class clsLearningFunctions<TMainInput, TNConnect, TMainOutput>
        where TMainInput : struct
        where TNConnect : struct
        where TMainOutput : struct
    {
        public delegate void InterNeuron(clsNetwork<TMainInput, TNConnect, TMainOutput> pntkNetwork);

        /// <summary>
        /// My own Learning function! Based on Hopfield requeriments of course
        /// </summary>
        /// <param name="pntkNetwork">The Network to apply the learning function</param>
        public static void LomasResearh(clsNetwork<TMainInput, TNConnect, TMainOutput> pntkNetwork)
        {
            InterNeuron dlgNeuron = delegate(clsNetwork<TMainInput, TNConnect, TMainOutput> pntkNeurons)
            {
                for (int i = 0; i < 60; i++)
                {
                    for (int j = 0; j < 60; j++)
                    {
                        if (i != j)
                        {
                            //distance based relation                        
                            if (pntkNeurons.InputLayers[0].Neurons[i].Axon.Equals(pntkNetwork.InputLayers[0].Neurons[j].Axon))
                            {
                                pntkNeurons.InputLayers[0].Neurons[i].Weights[j] += (j != 0) ? (1 / (j * 2)) : (1 / (i * 2));
                                pntkNeurons.InputLayers[0].Neurons[j].Weights[i] += (i != 0) ? (1 / (i * 2)) : (1 / (j * 2));
                            }
                            else
                            {
                                pntkNeurons.InputLayers[0].Neurons[i].Weights[j] -= (j != 0) ? (1 / (j * 2)) : (1 / (i * 2));
                                pntkNeurons.InputLayers[0].Neurons[j].Weights[i] -= (i != 0) ? (1 / (i * 2)) : (1 / (j * 2));
                            }
                        }
                    }
                }            
            };

            DataTable mdtbExamples;
            DataTable mdtbKeys;
            DataTable mdtbResults;

            SqlConnection sqlCon = new SqlConnection(ConfigurationManager.ConnectionStrings["GeneralExample"].ConnectionString);
            SqlDataAdapter sqlAda = new SqlDataAdapter("select * from vExamples", sqlCon);
            mdtbExamples = new DataTable();
            mdtbKeys = new DataTable();
            sqlAda.Fill(mdtbExamples);
            sqlAda.SelectCommand.CommandText = "select * from vExamples where [Key] = 1";
            sqlAda.Fill(mdtbKeys);
            mdtbResults = mdtbExamples.Copy();

            for (int i = 0; i < mdtbExamples.Rows.Count; i++)
            {
                for (int j = 0; j < 60; j++)
                {
                    pntkNetwork.InputLayers[0].Neurons[j].Dendrites[0] = (TMainInput)Convert.ChangeType(mdtbExamples.Rows[i][j], typeof(TMainInput));
                }

                for (int j = 0; j < 60; j++)
                {
                    mdtbResults.Rows[i][j] = pntkNetwork.InputLayers[0].Neurons[j].Axon;
                }
            }

            for (int i = 0; i < mdtbExamples.Rows.Count; i++)
            {
                for (int j = 0; j < 60; j++)
                {
                    if (Convert.ToInt32(mdtbKeys.Rows[int.Parse(mdtbResults.Rows[i]["O1"].ToString())][j]) != Convert.ToInt32(mdtbResults.Rows[i][j]))
                    {
                        if (Convert.ToInt32(mdtbExamples.Rows[i][j]) == 1)
                        {
                            pntkNetwork.InputLayers[0].Neurons[j].Weights[0] -= 0.65;
                        }
                        else
                        {
                            pntkNetwork.InputLayers[0].Neurons[j].Weights[0] += 0.65;
                        }
                    }
                }
                dlgNeuron(pntkNetwork);
            }
            
        }
    }
}
